package com.powernode.service.impl;

import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.powernode.constant.BusinessEnum;
import com.powernode.constant.QueueConstants;
import com.powernode.domain.*;
import com.powernode.ex.handler.BusinessException;
import com.powernode.feign.OrderBasketFeign;
import com.powernode.feign.OrderMemberFeign;
import com.powernode.feign.OrderProdFeign;
import com.powernode.mapper.OrderItemMapper;
import com.powernode.mapper.OrdersListMapper;
import com.powernode.model.*;
import com.powernode.service.OrderItemService;
import com.powernode.service.OrdersListService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.powernode.util.AuthUtils;
import com.powernode.vo.OrderStatusCount;
import com.powernode.vo.OrderVo;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * <p>
 * 订单表 服务实现类
 * </p>
 *
 * @author 付作巍
 * @since 2024-08-19
 */
@Service
@Transactional
public class OrdersListServiceImpl extends ServiceImpl<OrdersListMapper, OrdersList> implements OrdersListService {

    @Autowired
    private OrdersListMapper orderMapper;

    @Autowired
    private OrderItemMapper orderItemMapper;

    @Autowired
    private OrderMemberFeign orderMemberFeign;  //订单调用会员feign

    @Autowired
    private OrderProdFeign orderProdFeign;  //订单调用商品的feign

    @Autowired
    private OrderBasketFeign orderBasketFeign;  //订单调用购物车的feign

    @Autowired
    private Snowflake snowflake;

    @Autowired
    private OrderItemService orderItemService;

    @Autowired
    private RabbitTemplate rabbitTemplate;      // 注入mq

    /**
     * 多条件分页查询订单
     * @param page page分页对象
     * @param orderNumber 订单编号
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @param status 状态
     * @return 分页
     */
    @Override
    public Page<OrdersList> queryOrderPage(Page<OrdersList> page, String orderNumber, Integer status, Date startTime, Date endTime) {
        // 多条件分页查询订单列表(不考虑订单条目)
        page = orderMapper.selectPage(page,new LambdaQueryWrapper<OrdersList>()
                .eq(ObjectUtil.isNotNull(status), OrdersList::getStatus,status)
                .between(ObjectUtil.isAllNotEmpty(startTime,endTime), OrdersList::getCreateTime,startTime,endTime)        //在开始时间和结时间之间
                .eq(StringUtils.hasText(orderNumber), OrdersList::getOrderNumber,orderNumber)
                .orderByDesc(OrdersList::getCreateTime)
        );

        // 从订单分页对象中获取订单记录
        List<OrdersList> orderList = page.getRecords();
        // 判断是否有值
        if (CollectionUtils.isEmpty(orderList) || orderList.size() == 0){   //没有，直接返回page对象
            return page;
        }
        // 有值
            // 从订单记录集合中获取订单编号集合
        List<String> orderNumberList = orderList.stream().map(OrdersList::getOrderNumber).collect(Collectors.toList());
        // 根据订单编号查询所有订单商品条目对象集合
        List<OrderItem> orderItemList = orderItemMapper.selectList(new LambdaQueryWrapper<OrderItem>()
                .in(OrderItem::getOrderNumber, orderNumberList)
        );
        // 循环遍历订单记录集合
        orderList.forEach(order -> {
            // 从订单商品条目集合中过滤出与当前订单记录的订单编号一致的商品条目对象集合
            List<OrderItem> itemList = orderItemList.stream().filter(orderItem -> orderItem.getOrderNumber().equals(order.getOrderNumber())).collect(Collectors.toList());

            order.setOrderItems(itemList);
        });
        return page;
    }

    /**
     * 根据订单编号查询详细订单信息
     * @param orderNumber 订单编号
     * @return
     */
    @Override
    public OrdersList queryOrderListsDetailByOrderNumber(Long orderNumber) {
        // 根据订单编号查询订单信息
        OrdersList ordersList = orderMapper.selectOne(new LambdaQueryWrapper<OrdersList>()
                .eq(OrdersList::getOrderNumber, orderNumber)
        );
        // 根据订单编号查询订单商品条目对象集合
        List<OrderItem> orderItemList = orderItemMapper.selectList(new LambdaQueryWrapper<OrderItem>()
                .eq(OrderItem::getOrderNumber, orderNumber)
        );
        // 将订单编号查询订单商品条目对象集合值赋值给订单
        ordersList.setOrderItems(orderItemList);
        // 从订单记录中获取订单收货地址标识(用户订单收获地址id)
        Long addrOrderId = ordersList.getAddrOrderId();
        // 根据收货地址标识查询地址详情(远程调用,订单调用会员)
        Result<MemberAddr> result = orderMemberFeign.getMemberAddrById(addrOrderId);
        // 判断结果
        if(result.getCode().equals(BusinessEnum.OPERATION_FAIL.getCode())){
            throw new BusinessException("远程接口调用失败：根据收获地址标识查询收获地址信息");
        }
        // 获取数据
        MemberAddr memberAddr = result.getData();
        ordersList.setUserAddrOrder(memberAddr);

        // 根据会员openID查询会员昵称(远程接口)
        Result<String> result1 = orderMemberFeign.getNickNameByOpenId(ordersList.getOpenId());
        if (result1.getCode().equals(BusinessEnum.OPERATION_FAIL.getCode())){
            throw new BusinessException("远程接口调用失败：根据会员openId查询会员昵称");
        }
        // 获取数据
        String nickName = result1.getData();
        ordersList.setNickName(nickName);

        return ordersList;
    }

    /**
     * 查询订单各个状态数量
     * @return
     */
    @Override
    public OrderStatusCount queryMemberOrderStatusCount() {
        // 获取会员的openid
        String openId = AuthUtils.getMemberOpenId();

        // 根据会员openid查询待支付订单数量
        Long unPay = orderMapper.selectCount(new LambdaQueryWrapper<OrdersList>()
                .eq(OrdersList::getOpenId,openId)
                .eq(OrdersList::getStatus,1)
        );

        // 根据会员openid查询待发货订单数量
        Long payed = orderMapper.selectCount(new LambdaQueryWrapper<OrdersList>()
                .eq(OrdersList::getOpenId,openId)
                .eq(OrdersList::getStatus,2)
        );

        // 根据会员openid查询待收货订单数量
        Long consignment = orderMapper.selectCount(new LambdaQueryWrapper<OrdersList>()
                .eq(OrdersList::getOpenId,openId)
                .eq(OrdersList::getStatus,3)
        );

        return OrderStatusCount.builder()
                .unPay(unPay).payed(payed).consignment(consignment)
                .build();
    }

    /**
     * 分页查询会员订单列表
     * @param current 当前页码
     * @param size 每页显示数
     * @param status 状态:0全部，1待支付，2待发货，3待收货
     * @return
     */
    @Override
    public Page<OrdersList> queryMemberOrderPage(Long current, Long size, Long status) {
        // 获取会员的openid
        String openId = AuthUtils.getMemberOpenId();

        // 创建一个订单分页对象
        Page<OrdersList> page = new Page<>();
        // 分页查询会员订单列表
        page = orderMapper.selectPage(page,new LambdaQueryWrapper<OrdersList>()
                .eq(OrdersList::getOpenId,openId)
                .eq(0 != status,OrdersList::getStatus,status)
                .eq(OrdersList::getDeleteStatus,0)  // 查看没有删除的订单
                .orderByDesc(OrdersList::getCreateTime)
        );

        // 从订单分页对象中获取订单记录集合
        List<OrdersList> ordersLists = page.getRecords();
        // 判断是否有值
        if (CollectionUtils.isEmpty(ordersLists) || ordersLists.size() == 0){
            return page;
        }

        // 有值
        // 从订单集合中获取订单编号集合
        List<String> orderNumberList = ordersLists.stream().map(OrdersList::getOrderNumber).collect(Collectors.toList());

        // 根据订单编号集合查询订单商品条目集合
        List<OrderItem> orderItemList = orderItemMapper.selectList(new LambdaQueryWrapper<OrderItem>()
                .in(OrderItem::getOrderNumber, orderNumberList)
        );

        // 循环遍历订单集合
        ordersLists.forEach(ordersList -> {
            // 从所有商品条目对象集合中过滤出与当前订单编号一致的商品条目对象集合
            List<OrderItem> orderItemStream = orderItemList.stream()
                    .filter(orderItem -> orderItem.getOrderNumber().equals(ordersList.getOrderNumber()))
                    .collect(Collectors.toList());

            ordersList.setOrderItemDtos(orderItemStream);
        });
        return page;
    }

    /**
     * 根据订单编号查询订单详情信息
     * @param orderNumber 订单编号
     * @return
     */
    @Override
    public OrdersList queryMemberOrderDetailByOrderNumber(String orderNumber) {
        // 根据订单编号查询订单信息
        OrdersList ordersList = orderMapper.selectOne(new LambdaQueryWrapper<OrdersList>()
                .eq(OrdersList::getOrderNumber, orderNumber)
        );

        // 判断订单是否存在
        if (ObjectUtil.isNull(ordersList)){
            throw new BusinessException("订单编号有误 ！！");
        }

        // 查询订单收货地址对象(远程调用,订单调会员)
        Result<MemberAddr> result = orderMemberFeign.getMemberAddrById(ordersList.getAddrOrderId());

        // 判断
        if (BusinessEnum.OPERATION_FAIL.getCode().equals(result.getCode())){
            throw new BusinessException("返回查询订单收货地址失败 ！");
        }
        // 有，获取收货地址信息
        MemberAddr memberAddr = result.getData();
        // 赋值
        ordersList.setUserAddrDto(memberAddr);

        // 根据订单编号查询订单商品条目集合
        List<OrderItem> orderItemList = orderItemMapper.selectList(new LambdaQueryWrapper<OrderItem>()
                .eq(OrderItem::getOrderNumber, orderNumber)
        );
        ordersList.setOrderItemDtos(orderItemList);
        return ordersList;
    }

    /**
     * 会员确认收货
     * @param orderNumber 订单编号
     * @return
     */
    @Override
    public Boolean receiptMemberOrder(String orderNumber) {
        // 创建一个订单对象
        OrdersList ordersList = new OrdersList();
        ordersList.setUpdateTime(new Date());
        ordersList.setFinallyTime(new Date());
        ordersList.setStatus(5);
        return orderMapper.update(ordersList,new LambdaQueryWrapper<OrdersList>()
                .eq(OrdersList::getOrderNumber,orderNumber)
        ) > 0;
    }

    /**
     * 删除已经完成的订单(更改订单状态)
     * @param orderNumber 订单编号
     * @return
     */
    @Override
    public Boolean removeMemberOrderByOrderNumber(String orderNumber) {
        OrdersList ordersList = new OrdersList();
        ordersList.setUpdateTime(new Date());
        ordersList.setDeleteStatus(1);
        return orderMapper.update(ordersList,new LambdaQueryWrapper<OrdersList>()
                .eq(OrdersList::getOrderNumber,orderNumber)
        ) > 0;
    }

    /**
     * 查询会员确认订单页面数据
     * @param orderConfirmParam 订单确认页面参数对象
     * @return
     */
    @Override
    public OrderVo queryMemberOrderConfirmVo(OrderConfirmParam orderConfirmParam) {
        // 创建订单确认页面对象
        OrderVo orderVo = new OrderVo();
        // 获取会员openid
        String openId = AuthUtils.getMemberOpenId();
        // 根据会员openid查询会员默认收货地址(远程调用)
        Result<MemberAddr> result = orderMemberFeign.getMemberDefaultAddrByOpenId(openId);
        // 判断查询结果
        if (result.getCode().equals(BusinessEnum.OPERATION_FAIL.getCode())){
            throw new BusinessException("远程调用失败：根据会员openid查询会员默认收货地址");
        }
        // 调用成功，获取数据
        MemberAddr memberAddr = result.getData();
        orderVo.setMemberAddr(memberAddr);

        // 从订单确认页面参数对象中获取购物车id集合
        List<Long> basketIds = orderConfirmParam.getBasketIds();
        // 判断订单确认页面请求来自于哪里
        if (CollectionUtils.isEmpty(basketIds) || basketIds.size() ==0){
            // 购物车id集合为空，说明请求来自于商品详情页面
            productToOrderConfirm(orderConfirmParam.getOrderItem(),orderVo);
        }else {
            // 购物车id集合不为空，说明请求来自于购物车页面
            orderVo.setSource(1);
            cartToOrderConfirm(basketIds,orderVo);

        }
        return orderVo;
    }


    /**
     *  处理请求来自于购物车页面
     *      参数：购物车id---->购物车记录---->购物车商品数量
     *                              ----->商品skuid---->商品sku对象 ----> 有了商品的单价----> 算出总金额
     *  购物车商品数量和商品单价 -> 单个商品的总金额 -> 所有单个商品的总金额的和
     * @param basketIds 购物车id
     * @param orderVo 购物车页面对象
     */
    private void cartToOrderConfirm(List<Long> basketIds, OrderVo orderVo) {
        // 判断购物车id是否有值
        if (CollectionUtils.isEmpty(basketIds) || basketIds.size() == 0){   //为空，
            return;
        }
        // 不为空，根据购物车id集合查询购物车对象集合(远程调用)
        Result<List<Basket>> result = orderBasketFeign.getBasketListByIds(basketIds);
        // 判断操作结果
        if (result.getCode().equals(BusinessEnum.OPERATION_FAIL.getCode())){
            throw new BusinessException("远程调用接口失败：根据购物车id集合查询购物车对象集合失败");
        }
        // 成功，获取数据
        List<Basket> basketList = result.getData();   //购物车对象集合
        // 从购物车对象集合中获取商品skuId集合
        List<Long> skuIdList = basketList.stream().map(Basket::getSkuId).collect(Collectors.toList());
        // 根据商品skuid集合查询商品sku对象集合(远程调用)
        Result<List<Sku>> skuResult = orderProdFeign.getSkuListBySkuIds(skuIdList);
        // 判断操作结果
        if (skuResult.getCode().equals(BusinessEnum.OPERATION_FAIL.getCode())){
            throw new BusinessException("远程调用失败：根据商品skuid集合查询商品sku对象集合");
        }
        // 成功，获取数据
        List<Sku> skuList = skuResult.getData();

        // 创建订单店铺对象集合
        List<ShopOrder> shopOrderList = new ArrayList<>();

        // 将购物车记录集合按照店铺标识进行分组
        Map<Long, List<Basket>> allShopOrderMap = basketList.stream().collect(Collectors.groupingBy(Basket::getShopId));

        // 创建所有单个商品总金额集合
        List<BigDecimal> oneSkuTotalAmounts = new ArrayList<>();
        // 创建一个所有单个商品购买数量集合
        List<Integer> oneSkuCounts = new ArrayList<>();

        // 循环遍历所有订单店铺map集合  shopId:店铺标识；baskets:购物车对象集合
        allShopOrderMap.forEach((shopId,baskets) -> {
            // 每循环一次就是一个店铺，创建一个订单店铺对象
            ShopOrder shopOrder = new ShopOrder();

            // 创建一个订单商品条目对象集合
            List<OrderItem> orderItemList = new ArrayList<>();
            // 循环遍历当前订单店铺对象的购物车记录集合
            baskets.forEach(basket -> {
                // 商品购买数量
                Long prodCount = basket.getProdCount();
                oneSkuCounts.add(Math.toIntExact(prodCount));
                // 商品id
                Long prodId = basket.getProdId();
                // 获取商品skuid
                Long skuId = basket.getSkuId();
                // 创建一个订单商品条目对象
                OrderItem orderItem = new OrderItem();
                orderItem.setProdCount(Math.toIntExact(prodCount));
                orderItem.setShopId(shopId);
                orderItem.setCommSts(0);
                orderItem.setProdId(prodId);
                orderItem.setSkuId(skuId);
                orderItem.setCreateTime(new Date());
                // 从商品sku对象集合中过滤出于当前购物车记录中的skuid一致的商品sku对象
                Sku sku1 = skuList.stream()
                        .filter(sku -> sku.getSkuId().equals(skuId))
                        .collect(Collectors.toList()).get(0);
                // 将商品sku1对象的属性值copy到订单商品条目对象中去
                BeanUtils.copyProperties(sku1,orderItem);
                // 计算单个商品总金额
                BigDecimal oneSkuAmount = sku1.getPrice().multiply(new BigDecimal(prodCount));
                orderItem.setProductTotalAmount(oneSkuAmount);
                oneSkuTotalAmounts.add(oneSkuAmount);
                orderItemList.add(orderItem);
            });

            shopOrder.setShopId(shopId);
            shopOrder.setShopOrderItems(orderItemList);
            shopOrderList.add(shopOrder);       //添加到店铺对象
        });

        // 计算所有商品购买数量总和
        Integer allSkuCount = oneSkuCounts.stream().reduce(Integer::sum).get();
        orderVo.setTotalCount(allSkuCount);
        // 计算所有商品总金额
        BigDecimal allSkuTotalAmount = oneSkuTotalAmounts.stream().reduce(BigDecimal::add).get();
        orderVo.setTotal(allSkuTotalAmount);
        orderVo.setActualTotal(allSkuTotalAmount);
        // 判断是否需要运费
        if (allSkuTotalAmount.compareTo(new BigDecimal(99)) == -1){ //运费
            orderVo.setTransfee(new BigDecimal(6));
            orderVo.setActualTotal(allSkuTotalAmount.add(new BigDecimal(6)));
        }

        orderVo.setShopCartOrders(shopOrderList);
    }

    /**
     * 处理请求来自于商品详情页面
     * @param orderItem 订单详情
     * @param orderVo 订单封装对象
     */
    private void productToOrderConfirm(OrderItem orderItem, OrderVo orderVo) {
        // 取出订单店铺id
        Long shopId = orderItem.getShopId();
        // 创建订单店铺对象集合
        List<ShopOrder> shopOrderList = new ArrayList<>();
        // 创建一个订单店铺对象
        ShopOrder shopOrder = new ShopOrder();
        // 创建订单商品条目对象集合
        List<OrderItem> orderItemList = new ArrayList<>();

        // 获取商品skuid
        Long skuId = orderItem.getSkuId();
        // 根据商品skuid查询商品sku对象(远程调用)
        Result<List<Sku>> result = orderProdFeign.getSkuListBySkuIds(Arrays.asList(skuId));
        // 判断操作结果
        if (result.getCode().equals(BusinessEnum.OPERATION_FAIL.getCode())){
            throw new BusinessException("远程调用接口失败：根据商品skuid查询商品sku对象");
        }
        // 没有失败，获取数据
        List<Sku> skuList = result.getData();
        // 获取商品sku对象
        Sku sku = skuList.get(0);

        // 获取商品总数量
        Integer prodCount = orderItem.getProdCount();
        // 计算单个商品总金额
        BigDecimal oneSkuTotalAmount = sku.getPrice().multiply(new BigDecimal(prodCount));

        // 给订单商品条目对象属性赋值
        orderItem.setShopId(shopId);
        orderItem.setCreateTime(new Date());
        orderItem.setCommSts(0);
        orderItem.setProductTotalAmount(oneSkuTotalAmount);

        // 将商品sku对象的属性值copy到订单商品条目对象中去
        BeanUtils.copyProperties(sku,orderItem);

        orderItemList.add(orderItem);
        shopOrder.setShopId(shopId);
        shopOrder.setShopOrderItems(orderItemList);

        shopOrderList.add(shopOrder);
        // 补充订单确认页面对象数据
        orderVo.setShopCartOrders(shopOrderList);
        orderVo.setTotal(oneSkuTotalAmount);
        orderVo.setTotalCount(prodCount);
        orderVo.setActualTotal(oneSkuTotalAmount);
        if (oneSkuTotalAmount.compareTo(new BigDecimal(99)) == -1){ //运费
            orderVo.setTransfee(new BigDecimal(6));
            orderVo.setActualTotal(oneSkuTotalAmount.add(new BigDecimal(6)));
        }
    }


    /**
     * 会员提交订单
     *      1:判断订单请求的来源，如果请求来自购物车页面，需要将购买的商品在购物车中的记录给删除掉(如果来自商品详情页就不用管理)
     *      2:修改商品prod和sku的库存数量 -> 返回:修改商品prod和sku的库存数量值
     *      3:写订单(1.写订单表(orders_list)   2.写订单商品条目表(order_item))
     *      4:解决超时未支付问题(通过延迟队列和死信队列来处理超时未处理问题)
     * @param orderVo 订单确认对象
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public String submitOrder(OrderVo orderVo) {
        // 获取会员openId
        String openId = AuthUtils.getMemberOpenId();
        // 获取订单请求来源标识
        Integer source = orderVo.getSource();
        // 判断请求来源
        if (1 == source){
            // 说明：提交订单的请求于购物车页面 ----> 删除会员购买商品在购物车中的记录
            clearMemberCheckedBasket(openId,orderVo);
        }
        // 修改商品prod和sku的库存数量
        ChangeStock changeStock = changeProdAndSkuStock(orderVo);
        //生成一个全局唯一的订单编号（使用雪花算法）
        String orderNumber = generateOrderMember();
        // 写订单(写订单表orders_list和订单商品条目表order_item)
        writeOrder(openId,orderNumber,orderVo);

        // 解决超时未支付的问题。写延迟队列
        sendMsMsg(orderNumber,changeStock);

        return orderNumber;
    }



    /**
     * 雪花算法生成一个全局唯一的订单编号
     * @return
     */
    private String generateOrderMember() {
        return snowflake.nextIdStr();
    }


    /**
     * 会员提交订单的请求于购物车页面 ----> 删除会员购买商品在购物车中的记录
     * @param openId 会员openId
     * @param orderVo 订单对象
     */
    private void clearMemberCheckedBasket(String openId, OrderVo orderVo) {
        // 创建一个所有商品skuId集合
        List<Long> allSkuIds = new ArrayList<>();
        // 获取订单店铺对象集合
        List<ShopOrder> shopOrderList = orderVo.getShopCartOrders();
        // 循环遍历订单店铺对象集合
        shopOrderList.forEach(shopOrder -> {
            // 获取店铺对象的订单商品条目对象集合
            List<OrderItem> orderItems = shopOrder.getShopOrderItems();
            // 从订单商品条目对象集合中获取商品skuId集合
            List<Long> skuIdList = orderItems.stream()
                    .map(OrderItem::getSkuId).collect(Collectors.toList());

            allSkuIds.addAll(skuIdList);
        });
        // 准备参数,获取会员openId和商品skuId
        Map<String,Object> param = new HashMap<>();
        param.put("openId",openId);
        param.put("skuIdList",allSkuIds);
        // 根据会员openId和商品skuId集合删除购物车记录(远程调用:订单调用购物车)
        Result<Boolean> result = orderBasketFeign.removeBasketByOpenIdAndSkuIds(param);
        // 判断操作是否成功
        if (result.getCode().equals(BusinessEnum.OPERATION_FAIL.getCode())){
            throw new BusinessException("远程调用接口失败：根据会员openId和商品skuId集合删除购物车记录");
        }

    }

    /**
     * 会员提交订单：修改prod和sku的库存数量
     * @param orderVo 订单对象
     * @return
     */
    private ChangeStock changeProdAndSkuStock(OrderVo orderVo) {
        // 创建商品prod购买数量集合
        List<ProdChange> prodChangeList = new ArrayList<>();
        // 创建商品sku购买数量集合
        List<SkuChange> skuChangeList = new ArrayList<>();
        // 获取订单店铺对象集合
        List<ShopOrder> shopOrderList = orderVo.getShopCartOrders();
        // 循环遍历店铺对象集合
        shopOrderList.forEach(shopOrder -> {
            // 获取店铺的订单商品条目对象集合
            List<OrderItem> orderItems = shopOrder.getShopOrderItems();
            // 循环订单商品条目对象集合 ---> 获取每一个订单的skuId，prodId 和数量
            orderItems.forEach(orderItem -> {
                // 获取商品prodId
                Long prodId = orderItem.getProdId();
                // 获取商品skuid
                Long skuId = orderItem.getSkuId();
                // 获取商品购买数量
                Integer prodCount = orderItem.getProdCount()*-1;

                // 判断商品prod是否在prodChangeList集合中出现过
                List<ProdChange> oneProdChange = prodChangeList.stream()
                        .filter(prodChange -> prodChange.getProdId().equals(prodId)).collect(Collectors.toList());
                if (CollectionUtils.isEmpty(oneProdChange) || oneProdChange.size() ==0){
                    // 说明当前订单商品条目对象的商品prodId没有出现过
                    // 创建商品prod购买数量对象
                    ProdChange prodChange = new ProdChange(prodId,prodCount);
                    // 创建商品sku购买数量对象
                    SkuChange skuChange = new SkuChange(skuId,prodCount);

                    // 赋值
                    prodChangeList.add(prodChange);
                    skuChangeList.add(skuChange);
                }else {
                    // 说明当前订单商品条目对象的商品prodId在之前出现过
                    // 获取之前的prodChange
                    ProdChange beforeProdChange = oneProdChange.get(0);
                    // 计算商品prod一共购买的数量
                    int finalCount = beforeProdChange.getCount() + prodCount;
                    beforeProdChange.setCount(finalCount);

                    // 创建商品sku购买数量
                    SkuChange skuChange = new SkuChange(skuId,prodCount);
                    skuChangeList.add(skuChange);
                }
            });
        });

        // 创建商品购买数量
        ChangeStock changeStock = new ChangeStock(prodChangeList,skuChangeList);

        // 远程调用：修改商品prod和sku的库存数量，订单调用商品
        Result<Boolean> result = orderProdFeign.changeProdAndSkuStock(changeStock);
        // 判断操作结果
        if (result.getCode().equals(BusinessEnum.OPERATION_FAIL.getCode())){
            throw new BusinessException("修改商品prod和sku的库存数量失败!!!");
        }
        // 没问题
        Boolean resultData = result.getData();
        if (!resultData){
            throw  new BusinessException("修改商品prod和sku的库存数量失败!!!");
        }

        return changeStock;
    }


    /**
     * 会员提交订单：写订单(写订单表orders_list和订单商品条目表order_item)
     * @param openId 会员标识
     * @param orderNumber 订单编号
     * @param orderVo 订单对象
     */
    private void writeOrder(String openId, String orderNumber, OrderVo orderVo) {
        // 创建所有订单商品条目对象集合
        List<OrderItem> allOrderItemList = new ArrayList<>();
        // 获取订单店铺对象集合
        List<ShopOrder> shopOrderList = orderVo.getShopCartOrders();
        // 循环遍历订单店铺对象集合
        shopOrderList.forEach(shopOrder -> {
            // 获取店铺对象的订单商品条目对象集合
            List<OrderItem> orderItemList = shopOrder.getShopOrderItems();
            // 循环遍历订单商品条目对象集合
            orderItemList.forEach(orderItem -> orderItem.setOrderNumber(orderNumber));
            // 收集所有订单商品条目集合
            allOrderItemList.addAll(orderItemList);
        });
        // 写订单商品条目表
        boolean saved = orderItemService.saveBatch(allOrderItemList);
        if (saved){
            // 写订单表orders_list
            OrdersList ordersList = new OrdersList();
            ordersList.setOpenId(openId);
            ordersList.setTotalMoney(orderVo.getTotal());
            ordersList.setOrderNumber(orderNumber);
            ordersList.setActualTotal(orderVo.getActualTotal());
            ordersList.setRemarks(orderVo.getRemark());
            ordersList.setStatus(1);
            ordersList.setFreightAmount(orderVo.getTransfee());
            ordersList.setAddrOrderId(orderVo.getMemberAddr().getAddrId());
            ordersList.setProductNums(orderVo.getTotalCount());
            ordersList.setCreateTime(new Date());
            ordersList.setUpdateTime(new Date());
            ordersList.setIsPayed(0);
            ordersList.setDeleteStatus(0);
            ordersList.setRefundSts(0);
            ordersList.setReduceAmount(orderVo.getShopReduce());
            orderMapper.insert(ordersList);
        }
    }


    /**
     * 会员提交订单：发送消息（使用延迟队列和死信队列解决超时未支付问题）
     * @param orderNumber 订单编号
     * @param changeStock 修改库存数量
     */
    private void sendMsMsg(String orderNumber, ChangeStock changeStock) {
        // 将数据存放到JSON对象中，并将JSON对象转换未json格式字符串
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("orderNumber",orderNumber);
        jsonObject.put("changeStock",changeStock);

        // 发送消息
        rabbitTemplate.convertAndSend(QueueConstants.ORDER_MS_QUEUE,jsonObject.toJSONString());
    }


    /**
     * 会员提交订单超时未支付订单：订单回滚
     * @param ordersList 订单
     * @param changeStock 修改库存数量
     */
    @Override
    public void orderRollBack(OrdersList ordersList, ChangeStock changeStock) {
        // 修改订单信息
        ordersList.setUpdateTime(new Date());
        ordersList.setFinallyTime(new Date());
        ordersList.setStatus(6);
        ordersList.setCloseType(1);
        orderMapper.updateById(ordersList);
        // 回滚商品prod和sku的库存
        List<ProdChange> prodChangeList = changeStock.getProdChangeList();
        prodChangeList.forEach(prodChange -> prodChange.setCount(prodChange.getCount()*-1));

        List<SkuChange> skuChangeList = changeStock.getSkuChangeList();
        skuChangeList.forEach(skuChange -> skuChange.setCount(skuChange.getCount()*-1));

        // 回滚prod和sku的库存
        Result<Boolean> result = orderProdFeign.changeProdAndSkuStock(changeStock);
        // 判断
        if (result.getCode().equals(BusinessEnum.OPERATION_FAIL.getCode())){
            // 失败
            throw new BusinessException("修改商品prod和sku数量，回滚商品库存数量失败 ！");
        }
    }

}
